// =====================================================================================
//	Copyright (C) 2019 by Jiaxing Shao.All rights reserved.
//	文 件 名:  websocket_server.h
//	作    者:  Jiaxing Shao, 13315567369@163.com
//	版 本 号:  1.0
//	创建时间:  2019年05月06日 18时14分46秒
//	Compiler:  g++
//	描    述:
// =====================================================================================

#ifndef _WEBSOCKET_SERVER_H_H_H
#define _WEBSOCKET_SERVER_H_H_H

#include <iostream>
#include <set>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
using namespace std;

typedef websocketpp::server<websocketpp::config::asio> server;
typedef server::message_ptr                            message_ptr;

using websocketpp::connection_hdl;
using websocketpp::lib::bind;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;

using websocketpp::lib::condition_variable;
using websocketpp::lib::lock_guard;
using websocketpp::lib::mutex;
using websocketpp::lib::thread;
using websocketpp::lib::unique_lock;

enum action_type {
    SUBSCRIBE,
    UNSUBSCRIBE,
    MESSAGE
};

struct action {
    action(action_type t, connection_hdl h) : type(t), hdl(h){};
    action(action_type t, connection_hdl h, server::message_ptr m) : type(t), hdl(h), msg(m){};

    action_type         type;
    connection_hdl      hdl;
    server::message_ptr msg;
};

class WebSocketServer
{
public:
    WebSocketServer();
    ~WebSocketServer();
    void start(int port);
    void on_open(connection_hdl hdl);
    void on_fail(connection_hdl hdl);
    void on_close(connection_hdl hdl);
    void on_message(connection_hdl hdl, message_ptr msg);

    void         send_message(char *pData, int nSize);
    static void *process_message(void *arg);

private:
    typedef std::set<connection_hdl, std::owner_less<connection_hdl>> conn_list;

    server        m_server;
    conn_list     m_connections;
    queue<action> m_actions;

    mutex              m_action_lock;
    mutex              m_connection_lock;
    condition_variable m_action_cond;
};

#endif
